/*
	This script file is part of the Sonic 3 A.I.R. script software distribution.
	Copyright (C) 2017-2024 by Eukaryot

	Published under the GNU GPLv3 open source software license, see license.txt
	or https://www.gnu.org/licenses/gpl-3.0.en.html
*/



//# address-hook(0x039f2e) end(0x039f78)
function void fn039f2e()
{
	bool flag = (objA0.subtype2c & 0x80)
	u16[A0 + 0x2c] = (objA0.subtype2c & 0x7f) * 8

	if (flag)
	{
		objA0.update_address = 0x03a0b0
		fn03a0b0()
	}
	else
	{
		objA0.update_address = 0x039f58
		fn039f58()
	}
}



// Horizontal cylinder

//# address-hook(0x039f58) end(0x039f78)
function void fn039f58()
{
	D4.u16 = u16[A0 + 0x2c]
	D5.u16 = D4.u16 * 2

	A1 = 0xffffb000
	A2 = 0xfffff7b0
	D6 = 3		// object.flag.P1_ON_OBJECT
	fn039f7e()

	A1 = 0xffffb04a
	A2 = 0xfffff7b1
	++D6.u8		// object.flag.P2_ON_OBJECT
	fn039f7e()

	CheckForUnloadObject()
}


//# address-hook(0x039f7e) end(0x03a0ae)
function void fn039f7e()
{
	bool isInside = (objA0.flags2a >> D6.u8) & 1
	u8 bit = (1 << D6.u8)

	if (!isInside)
	{
		D0.u16 = objA1.position.x.u16 - objA0.position.x.u16 + D4.u16
		if (D0.u16 < D5.u16)
		{
			if (!Game.getSetting(SETTING_FBZ_ENTERCYLINDER))
			{
				D0.u16 = objA1.position.y.u16 - objA0.position.y.u16 + 0x50
				if (D0.u16 < 0x18)
				{
					u8[A2 + 0x02] = 0x28
				}
			}

			if (u8[A2 + 0x02] != 0)
			{
				--u8[A2 + 0x02]
				return
			}

			D0.u16 = objA0.position.y.u16 + 0x3c
			D2.u16 = objA1.position.y.u16
			D1.u16 = D2.u16 + s8[A1 + 0x1e] + 4
			if (D0.u16 <= D1.u16)
			{
				D0.u16 -= D1.u16
				if (D0.u16 >= 0xfff0)
				{
					if (u8[A1 + 0x05] < 0x06 && debug_mode.state == 0)
					{
						D2.u16 += D0.u16
						D2.u16 += 0x03
						objA1.position.y.u16 = D2.u16
						LetSonicClimbOnObject()
						u8[A1 + 0x2d] = 0x80		// Set cylinder walking animation
						objA1.state.both = char.state.RUNNING2
						u8[A2] = 0
						u8[A2 + 0x02] = 0
						if (u16[A1 + 0x1c] == 0)
						{
							u16[A1 + 0x1c] = 0x01
						}
					}
				}
			}
		}
	}
	else
	{
		if ((u8[A1 + 0x2a] & char.flag.IN_AIR) == 0)
		{
			D0.u16 = objA1.position.x.u16 - objA0.position.x.u16 + D4.u16
			if (D0.u16 < D5.u16)
			{
				if ((u8[A1 + 0x2a] & char.flag.ON_OBJECT) == 0)
					return

				D0.u8 = u8[A2]
				LookupSinCos()
				D1.s32 = s32(D1.s16) * 0x2800
				D1 = (D1 << 16) + (D1 >> 16)
				D2.u16 = objA0.position.y.u16 + D1.u16
				D1 = u8[A1 + 0x1e]
				D1.u16 -= 0x13
				D2.u16 -= D1.u16
				objA1.position.y.u16 = D2.u16
				D0.u8 = u8[A2]
				u8[A1 + 0x27] = D0.u8		// Set x-rotation of character
				u8[A2] += 0x04
				if (u16[A1 + 0x1c] == 0)
				{
					u16[A1 + 0x1c] = 0x01
				}
				return
			}
		}
		else
		{
			D0.u8 = u8[A2] + 0x20
			if (D0.u8 < 0x40)
			{
				objA1.velocity.y >>= 1
			}
			else
			{
				objA1.velocity.y = 0
			}
		}

		u8[A1 + 0x2a] &= ~char.flag.ON_OBJECT
		objA0.flags2a &= ~bit
		u8[A1 + 0x30] = 0			// "char.rotation.x.count"
		u8[A1 + 0x31] = 0x04		// "char.rotation.x.speed"
		u8[A1 + 0x2a] |= char.flag.IN_AIR
		u8[A1 + 0x2d] = 0
	}
}



// Vertical cylinder

//# address-hook(0x03a0b0) end(0x03a0d0)
function void fn03a0b0()
{
	D4.u16 = u16[A0 + 0x2c]
	D5.u16 = D4.u16 * 2

	A1 = 0xffffb000
	A2 = 0xfffff7b0
	D6 = 3		// object.flag.P1_ON_OBJECT
	fn03a0d6()

	A1 = 0xffffb04a
	A2 = 0xfffff7b1
	++D6.u8		// object.flag.P2_ON_OBJECT
	fn03a0d6()

	CheckForUnloadObject()
}


//# address-hook(0x03a0d6) end(0x03a21a)
function void fn03a0d6()
{
	u8 bit = (1 << D6.u8)

	if ((objA0.flags2a & bit) == 0)
	{
		D0.u16 = objA1.position.x.u16 - objA0.position.x.u16 + 0x80
		if (D0.u16 >= 0x0100)
			return

		D1.u16 = objA1.position.y.u16 - objA0.position.y.u16 + D4.u16
		if (D1.u16 >= D5.u16)
			return

		if (u8[A1 + 0x05] >= 0x06 || debug_mode.state != 0 || s8[A1 + 0x2e] < 0)
			return

		if (D0.u16 >= 0x20 && D0.u16 < 0xe0)
			return

		fn033c34()
		u8[A1 + 0x26] = 0xc0
		objA1.render_flags &= ~render_flag.FLIP_X
		u8[A1 + 0x2a] &= ~0x01
		u8[A2] = 0

		D0.u16 = objA1.position.x.u16 - objA0.position.x.u16
		if (D0.s16 < 0)
		{
			u8[A2] = 0x80
		}
		objA1.groundspeed = -objA1.velocity.y

		D0.u16 = objA1.position.y.u16 - objA0.position.y.u16
		if (D0.s16 < 0)
		{
			u8[A1 + 0x26] = 0x40
			objA1.groundspeed = -objA1.groundspeed
		}
		u8[A1 + 0x2e] |= (control_flag.DISABLE_WALLS | control_flag.DISABLE_ANIMATION)
		objA1.state.both = char.state.RUNNING2
		u8[A1 + 0x27] = 0		// Reset x-rotation of character
		u8[A2 + 0x02] = 0
	}

	D1.u16 = objA1.position.y.u16 - objA0.position.y.u16 + D4.u16
	if (D1.u16 >= D5.u16)
	{
		u8[A1 + 0x2e] = 0
		u8[A1 + 0x2a] &= ~char.flag.ON_OBJECT
		objA0.flags2a &= ~bit
		u8[A1 + 0x27] = 0x01		// Set x-rotation of character
		u8[A1 + 0x30] = 0			// "char.rotation.x.count"
		u8[A1 + 0x31] = 0x04		// "char.rotation.x.speed"
		u8[A1 + 0x2a] |= char.flag.IN_AIR
		return
	}

	if ((u8[A1 + 0x2a] & char.flag.ON_OBJECT) == 0)
		return

	if (objA1.velocity.y >= 0)
		objA1.render_flags |= render_flag.FLIP_Y
	else
		objA1.render_flags &= ~render_flag.FLIP_Y

	D0.u8 = u8[A2]
	LookupSinCos()
	D1.s32 = s32(D1.s16) * 0x6800
	D1 = (D1 << 16) + (D1 >> 16)
	D2.u16 = objA0.position.x.u16 + D1.u16
	D1 = u8[A1 + 0x1e]
	D1.u16 -= 0x13
	D2.u16 -= D1.u16
	objA1.position.x.u16 = D2.u16
	D2 = u8[A2]
	u8[A2] += 4
	D2.u16 = D2 / 0x0b
	objA1.animation.sprite = u8[0x03a220 + D2.u16]		// Player characters' corkscrew vertical running sprites
	D0 = objA1.animation.sprite
	SetCharacterSpritePatterns()
}

